﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using Microsoft.Samples.Kinect.SwipeGestureRecognizer;
using Microsoft.Kinect.Toolkit.Interaction;
using ImaginativeUniversal.Kinect;
using System.Configuration;
using System.Diagnostics;
using System.ComponentModel;

namespace KinectKeyMapper
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        #region private members

        private KinectSensor _sensor;
        private Recognizer _swipeRecognizer;
        private InteractionStream _interactionStream;
        private UserInfo[] _userInfos;

        private readonly string SWIPE_RT_GRASP;
        private readonly string SWIPE_LFT_GRASP;
        private readonly string SWIPE_RT;
        private readonly string SWIPE_LFT;
        private readonly string DBL_GRASP;
        private readonly string DBL_PUSH;
        private readonly string PUSH_LFT;
        private readonly string PUSH_RT;

        #endregion

        public MainWindow()
        {
            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);

            InitializeComponent();

            try
            {
                WindowManagerHelper.ProcessName = ConfigurationManager.AppSettings["TargetApplicationProcessName"].ToString();
                SWIPE_RT_GRASP = ConfigurationManager.AppSettings["RightSwipeWithGraspAction"].ToString();
                SWIPE_LFT_GRASP = ConfigurationManager.AppSettings["LeftSwipeWithGraspAction"].ToString();
                DBL_GRASP = ConfigurationManager.AppSettings["DoubleGraspAction"].ToString();
                DBL_PUSH = ConfigurationManager.AppSettings["DoublePushAction"].ToString();
                SWIPE_RT = ConfigurationManager.AppSettings["RightSwipeNoGraspAction"].ToString();
                SWIPE_LFT = ConfigurationManager.AppSettings["LeftSwipeNoGraspAction"].ToString();
                PUSH_RT = ConfigurationManager.AppSettings["RightPush"].ToString();
                PUSH_LFT = ConfigurationManager.AppSettings["LeftPush"].ToString();
            }
            catch(Exception)
            {
                MessageBox.Show("Expected configuration settings are missing.  Please fix this and restart application.");
            }
        }

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            DeInitSensor(_sensor);
        }

        #region kinect setup

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            CreateSwipeGestureRecognizer(ref _swipeRecognizer);
            _userInfos = new UserInfo[InteractionFrame.UserInfoArrayLength];
            KinectSensor.KinectSensors.StatusChanged += new EventHandler<StatusChangedEventArgs>(KinectSensors_StatusChanged);
            _sensor = KinectSensor.KinectSensors.FirstOrDefault();
            InitSensor(_sensor);
            SetShadowImage();
        }

        private void SetShadowImage()
        {
            this.shadowImage.Source = _sensor.RenderPredatorView();

        }

        private void SendKeyStroke(string key)
        {
            WindowManagerHelper.SendKey(key);

            if(!string.IsNullOrEmpty(key))
                this.txtCommand.Text = key;
        }

        private void CreateSwipeGestureRecognizer(ref Recognizer recognizer)
        {
            recognizer = new Recognizer();
            recognizer.SwipeRightDetected  += (s, args) =>
            {
                SendKeyStroke(SWIPE_RT);
                if (IsRightGripped)
                {
                    SendKeyStroke(SWIPE_RT_GRASP);
                }
            };


            recognizer.SwipeLeftDetected += (s, args) =>
            {
                SendKeyStroke(SWIPE_LFT);
                if (IsLeftGripped)
                {
                    SendKeyStroke(SWIPE_LFT_GRASP);
                }
            };
        }


        void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            if (e.Status == KinectStatus.Disconnected)
            {
                if (_sensor != null)
                {
                    DeInitSensor(_sensor);
                }
            }

            if (e.Status == KinectStatus.Connected)
            {
                _sensor = e.Sensor;
                InitSensor(_sensor);
                SetShadowImage();
            }
        }

        void interactionStream_InteractionFrameReady(object sender, InteractionFrameReadyEventArgs e)
        {
            using (var frame = e.OpenInteractionFrame())
            {
                if (frame == null)
                    return;

                frame.CopyInteractionDataTo(_userInfos);
                if (_userInfos != null && _userInfos.Length > 0)
                {
                    bool rightHandPress = false;
                    bool leftHandPress = false;
                    bool rightHandGrip = false;
                    bool leftHandGrip = false;
                    bool rightHandRelease = false;
                    bool leftHandRelease = false;

                    foreach (var info in _userInfos)
                    {
                        foreach (var hand in info.HandPointers)
                        {
                            if (hand.HandType == InteractionHandType.Right)
                            {
                                if (!rightHandPress && hand.IsPressed)
                                    rightHandPress = true;
                                if (!rightHandGrip && hand.HandEventType == InteractionHandEventType.Grip)
                                    rightHandGrip = true;
                                if (!rightHandRelease && hand.HandEventType == InteractionHandEventType.GripRelease)
                                    rightHandRelease = true;
                            }

                            if (hand.HandType == InteractionHandType.Left)
                            {
                                if (!leftHandPress && hand.IsPressed)
                                    leftHandPress = true;
                                if (!leftHandGrip && hand.HandEventType == InteractionHandEventType.Grip)
                                    leftHandGrip = true;
                                if (!leftHandRelease && hand.HandEventType == InteractionHandEventType.GripRelease)
                                    leftHandRelease = true;
                            }
                        }
                    }
                    AnalyzePresses(rightHandPress, leftHandPress);
                    AnalyzeGrips(rightHandGrip, rightHandRelease, leftHandGrip, leftHandRelease);
                }


                if (IsLeftGripped && IsRightGripped)
                {
                    if (!IsDoubleGripped)
                    {
                        IsDoubleGripped = true;
                        SendKeyStroke(DBL_GRASP);
                    }
                }
                else
                {
                    IsDoubleGripped = false;
                }

                if (IsLeftPressed && IsRightPressed)
                {
                    if (!IsDoublePressed)
                    {
                        IsDoublePressed = true;
                        SendKeyStroke(DBL_PUSH);
                    }
                }
                else
                {
                    IsDoublePressed = false;
                }
            }
        }

        private void AnalyzePresses(bool rightHandPress, bool leftHandPress)
        {
            if (!rightHandPress)
            {
                IsRightPressed = false;
            }
            else
            {
                IsRightPressed = true;
            }

            if (!leftHandPress)
            {
                IsLeftPressed = false;
            }
            else
            {
                IsLeftPressed = true;
            }
        }

        private static void AnalyzeGrips(bool rightHandGrip, bool rightHandRelease, bool leftHandGrip, bool leftHandRelease)
        {
            if (!rightHandGrip)
            {

                if (rightHandRelease)
                {
                    IsRightGripped = false;
                }
            }
            else
            {
                IsRightGripped = true;
            }

            if (!leftHandGrip)
            {
                if (leftHandRelease)
                {
                    IsLeftGripped = false;
                }
            }
            else
            {
                IsLeftGripped = true;
            }
        }

        private void InitSensor(KinectSensor sensor)
        {
            if (sensor == null)
                return;

                _interactionStream = new InteractionStream(_sensor, new InteractionClient());
                _interactionStream.InteractionFrameReady += new EventHandler<InteractionFrameReadyEventArgs>(interactionStream_InteractionFrameReady);

                sensor.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(sensor_DepthFrameReady);
                sensor.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(sensor_SkeletonFrameReady);

                sensor.ColorStream.Enable();
                sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
                sensor.SkeletonStream.Enable();
                sensor.Start();

        }

        void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;

                Skeleton[] skeletons = new Skeleton[frame.SkeletonArrayLength];
                frame.CopySkeletonDataTo(skeletons);
                var accelerometerReading = _sensor.AccelerometerGetCurrentReading();
                _interactionStream.ProcessSkeleton(skeletons, accelerometerReading, frame.Timestamp);
                _swipeRecognizer.Recognize(sender, frame, skeletons);

            }
        }

        void sensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame frame = e.OpenDepthImageFrame())
            {
                if (frame == null)
                    return;

                _interactionStream.ProcessDepth(frame.GetRawPixelData(), frame.Timestamp);
            }
        }


        private void DeInitSensor(KinectSensor sensor)
        {
            if (sensor == null)
                return;
            
            sensor.SkeletonFrameReady -= sensor_SkeletonFrameReady;
            sensor.DepthFrameReady -= sensor_DepthFrameReady;

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += (a,b) =>
            {
                sensor.Stop();

                sensor.SkeletonStream.Disable();
                sensor.DepthStream.Disable();
                sensor.ColorStream.Disable();

                sensor = null;
            };
            bw.RunWorkerAsync();

            if (_interactionStream != null)
            {
                _interactionStream.InteractionFrameReady -= interactionStream_InteractionFrameReady;
            }
        }

        #endregion

        #region properties

        public static bool IsRightGripped
        {
            get;
            set;
        }

        public static bool IsLeftGripped
        {
            get;
            set;
        }

        public static bool IsDoubleGripped
        {
            get;
            set;
        }

        private bool _isRightPressed;
        public bool IsRightPressed
        {
            get { return _isRightPressed; }
            set
            {
                if (_isRightPressed != value)
                {
                    _isRightPressed = value;
                    if(value == true)
                    {
                        SendKeyStroke(PUSH_RT);
                    }

                }
            }
        }

        private bool _isLeftPressed;
        public bool IsLeftPressed
        {
            get { return _isLeftPressed; }
            set
            {
                if (_isLeftPressed != value)
                {
                    _isLeftPressed = value;
                    if (value == true)
                    {
                        SendKeyStroke(PUSH_LFT);
                    }

                }
            }
        }

        public static bool IsDoublePressed
        {
            get;
            set;
        }

        #endregion

    }
}
